﻿using System;
using System.Collections.Generic;
using System.Linq;
using Bots.DungeonBuddy.Helpers;
using CommonBehaviors.Actions;
using FarmerJoe.Helpers.Logging;
using Styx;
using Styx.CommonBot;
using Styx.CommonBot.POI;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;

namespace FarmerJoe
{
    namespace Helpers
    {
        public static class Utils
        {
            public static LocalPlayer Me { get { return StyxWoW.Me; } }
            public static WoWUnit CT { get { return Me.CurrentTarget; } }
        }

        /*
        public static class Specialisation
        {
            private static LocalPlayer Me { get { return StyxWoW.Me; } }
            private static int _oldSpec = -1;
            private static int _spec = 0;

            public static int GetSpec
            {
                get
                {
                    _spec = Spec;
                    if (_spec != _oldSpec){_oldSpec = _spec;}
                    return _spec;
                }
            }

            public static string GetSpecAsClassSpecific
            {
                get
                {
                    int spec = GetSpec;

                    switch (Me.Class)
                    {
                            case WoWClass.Warlock:
                            return String.Format("{0}",(Enums.ClassSpecialisation.Warlock)spec);
                            break;

                            case WoWClass.Priest:
                            return String.Format("{0}", (Enums.ClassSpecialisation.Priest)spec);
                            break;
                    }

                    return "none";
                }
            }

            private static int Spec
            {
                get
                {
                    
                    if (Me.Level < 10) return 0;

                    switch (Me.Class)
                    {
                        case WoWClass.Warrior:
                            if (SpellManager.HasSpell("Mortal Strike")) return 1;
                            if (SpellManager.HasSpell("Bloodthirst")) return 2;
                            if (SpellManager.HasSpell("Shield Slam")) return 3;
                            break;
                        case WoWClass.Paladin:
                            if (SpellManager.HasSpell("Holy Shock")) return 1;
                            if (SpellManager.HasSpell("Avenger's Shield")) return 2;
                            if (SpellManager.HasSpell("Templar's Verdict")) return 3;
                            break;
                        case WoWClass.Hunter:
                            if (SpellManager.HasSpell("Kill Command")) return 1;
                            if (SpellManager.HasSpell("ADimed Shot")) return 2;
                            if (SpellManager.HasSpell("Explosive Shot")) return 3;
                            break;
                        case WoWClass.Rogue:
                            if (SpellManager.HasSpell("Mutilate")) return 1;
                            if (SpellManager.HasSpell("Blade Flurry")) return 2;
                            if (SpellManager.HasSpell("Hemorrhage")) return 3;
                            break;
                        case WoWClass.Priest:
                            if (SpellManager.HasSpell("Spirit Shell")) return 1;
                            if (SpellManager.HasSpell("Circle of Healing")) return 2;
                            if (SpellManager.HasSpell("Shadow Word: Pain")) return 3;
                            break;
                        case WoWClass.DeathKnight:
                            if (SpellManager.HasSpell("Heart Strike")) return 1;
                            if (SpellManager.HasSpell("Howling Blast")) return 2;
                            if (SpellManager.HasSpell("Scourge Strike")) return 3;
                            break;
                        case WoWClass.Shaman:
                            if (SpellManager.HasSpell("Lightning Bolt")) return 1;
                            if (SpellManager.HasSpell("Stormwstrike")) return 2;
                            if (SpellManager.HasSpell("Earth Shield")) return 3;
                            break;
                        case WoWClass.Mage:
                            if (SpellManager.HasSpell("Arcane Blast")) return 1;
                            if (SpellManager.HasSpell("Pyroblast")) return 2;
                            if (SpellManager.HasSpell("Summon Water Elemental")) return 3;
                            break;
                        case WoWClass.Warlock:
                            if (SpellManager.HasSpell("Agony")) return 1;
                            if (SpellManager.HasSpell("Metamorphosis")) return 2;
                            if (SpellManager.HasSpell("Immolate")) return 3;
                            break;
                        case WoWClass.Druid:
                            if (SpellManager.HasSpell("Wrath")) return 1;
                            if (SpellManager.HasSpell("Rake")) return 2;
                            if (SpellManager.HasSpell("Lacerate")) return 3;
                            if (SpellManager.HasSpell("Rejuvenation")) return 4;
                            break;
                    }

                    return 0;
                }
            }
        }
         */

        public static class Misc
        {
            
            public static Composite DebugTimer(string message)
            {
                return new Action(ret =>
                                      {
                                          if (!Timers.Exists("DebugTimer"))
                                          {
                                              Timers.Add("DebugTimer");
                                              Timers.Reset("DebugTimer");
                                          }

                                          Log.Write(Colours.InformativeColour, "=== [Debug "+ message +"] " + Timers.Elappsed("DebugTimer"));
                                          Timers.Reset("DebugTimer");

                                          return RunStatus.Failure;
                                      }
                    );
            }



            public static string LuaGetReturnValueString(string lua) { return Lua.GetReturnValues(lua, "stuff.lua")[0]; }

            public static Composite EnsureTarget()
            {
                return
                    new Decorator(ret => ClassParser.CCControlledTargeting, 
                                  new PrioritySelector(
                                      new Decorator(
                                          // DisableTankTargeting is a user-setting. NeedTankTargeting is an internal one. Make sure both are turned on.
                                          ret => //!FpswareSettings.Instance.DisableTankTargetSwitching && 
                                          Group.MeIsTank && Tanking.TargetingTimer.IsFinished && StyxWoW.Me.Combat && Tanking.Instance.FirstUnit != null && (StyxWoW.Me.CurrentTarget == null || StyxWoW.Me.CurrentTarget != Tanking.Instance.FirstUnit),
                                          new Sequence(
                                              // pending spells like mage blizard cause targeting to fail.
                                              new DecoratorContinue(ctx => StyxWoW.Me.CurrentPendingCursorSpell != null, new Action( ctx => Lua.DoString("SpellStopTargeting()"))),
                                              new Action( ret => { Logger.WriteDebug("Targeting first unit of TankTargeting"); Tanking.Instance.FirstUnit.Target(); }),
                                              Spells.WaitForLagDuration(),
                                              new Action(ret => Tanking.TargetingTimer.Reset()))),

                                      new PrioritySelector(
                                          ctx =>
                                              {
                                                  // We are making sure we have the proper target in all cases here.

                                                  // No target switching for tanks. They check for their own stuff above.
                                                  if (Group.MeIsTank)
                                                      // && !FpswareSettings.Instance.DisableTankTargetSwitching)
                                                      return null;

                                                  // Go below if current target is null or dead. We have other checks to deal with that
                                                  if (StyxWoW.Me.CurrentTarget == null || StyxWoW.Me.CurrentTarget.IsDead) return null;

                                                  // If the current target is in combat or has aggro towards us, it should be a valid target.
                                                  if (StyxWoW.Me.CurrentTarget.Combat || StyxWoW.Me.CurrentTarget.Aggro) return null;

                                                  // Check botpoi first and make sure our target is set to POI's object.
                                                  if (BotPoi.Current.Type == PoiType.Kill)
                                                  {
                                                      var obj = BotPoi.Current.AsObject;

                                                      if (obj != null)
                                                      {
                                                          if (StyxWoW.Me.CurrentTarget != obj) return obj;
                                                      }
                                                  }

                                                  // Make sure we have the proper target from Targeting. 
                                                  // The Botbase should give us the best target in targeting.
                                                  var firstUnit = Targeting.Instance.FirstUnit;

                                                  if (firstUnit != null)
                                                  {
                                                      if (StyxWoW.Me.CurrentTarget != firstUnit) return firstUnit;
                                                  }

                                                  return null;
                                              },
                                          new Decorator( ret => ret != null,
                                              new Sequence(
                                                  new Action( ret => Logging.Log.Write("Current target is not the best target. Switching to " + ((WoWUnit) ret).SafeName() + "!")),
                                                  new Action(ret => ((WoWUnit) ret).Target()),
                                                  new WaitContinue(2, ret => StyxWoW.Me.CurrentTarget != null && StyxWoW.Me.CurrentTarget == (WoWUnit) ret, 
                                                      new ActionAlwaysSucceed())))),






                                      new Decorator( ret => StyxWoW.Me.CurrentTarget == null || StyxWoW.Me.CurrentTarget.IsDead,
                                          new PrioritySelector(
                                              delegate
                                                  {
                                                      // If we have a RaF leader, then use its target.
                                                      WoWPlayer rafLeader = RaFHelper.Leader;
                                                      if (rafLeader != null && rafLeader.IsValid && !rafLeader.IsMe && rafLeader.Combat && rafLeader.CurrentTarget != null && rafLeader.CurrentTarget.IsAlive && !Blacklist.Contains(rafLeader.CurrentTarget))
                                                      {
                                                          return rafLeader;
                                                      }

                                                      // Check bot poi.
                                                      if (BotPoi.Current.Type == PoiType.Kill)
                                                      {
                                                          WoWUnit unit = BotPoi.Current.AsObject as WoWUnit;
                                                          if (unit != null && unit.IsAlive && !unit.IsMe && !Blacklist.Contains(unit))
                                                          {
                                                              return unit;
                                                          }
                                                      }

                                                      // Does the target list have anything in it? And is the unit in combat?
                                                      // Make sure we only check target combat, if we're NOT in a BG. (Inside BGs, all targets are valid!!)
                                                      WoWUnit firstUnit = Targeting.Instance.FirstUnit;
                                                      if (firstUnit != null && firstUnit.IsAlive && !firstUnit.IsMe && firstUnit.Combat && !Blacklist.Contains(firstUnit))
                                                      {
                                                          return firstUnit;
                                                      }

                                                      // Cache this query, since we'll be using it for 2 checks. No need to re-query it.
                                                      WoWUnit agroMob = ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where( p =>
                                                              !Blacklist.Contains(p) && p.IsHostile && !p.IsOnTransport && !p.IsDead && !p.Mounted && p.DistanceSqr <= 70*70 && (p.IsTargetingMeOrPet || p.IsTargetingMyPartyMember || p.IsTargetingMyRaidMember)).OrderBy(u => u.DistanceSqr)
                                                              //!p.Mounted && p.DistanceSqr <= 70*70 && p.Combat).OrderBy(u => u.DistanceSqr)
                                                              .FirstOrDefault();

                                                      return agroMob ?? null;
                                                  },

                                              // Make sure the target is VALID. If not, then ignore this next part. (Resolves some silly issues!)
                                              new Decorator(ret => ret != null,
                                                            new Sequence(
                                                                new Action(ret => Logging.Log.Write("Current target is invalid. Switching to " + ((WoWUnit)ret).SafeName() + "!")),
                                                                new Action(ret => ((WoWUnit) ret).Target()),
                                                                new WaitContinue(2, ret => StyxWoW.Me.CurrentTarget != null && StyxWoW.Me.CurrentTarget == (WoWUnit) ret, 
                                                                    new ActionAlwaysSucceed()))),
                                              new ActionAlwaysSucceed()))));
            }


        }
    }
}
